using System.Windows.Controls;
using MinoChat.ViewModels.Pages;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Input;

namespace MinoChat.Views.Pages;

//【重点】将动画赋予依赖属性，依赖属性的回调函数改变ScrollView的滚动属性
public partial class ChatPage : UserControl
{
    private ChatPageViewModel? _viewModel;
    // 阈值：距离底部多少像素算作"在底部附近"
    private const double ScrollThreshold = 100;
    // 防止滚动过程中重复触发
    private bool _isScrolling = false;

    public ChatPage(ChatPageViewModel viewModel)
    {
        InitializeComponent();
        DataContext = viewModel;
        _viewModel = viewModel;
        // 订阅消息集合变化事件
        _viewModel.ChatMessages.CollectionChanged += OnMessagesCollectionChanged;
        // 订阅页面加载事件，页面加载完成时消息列表滚动到底部
        Loaded += OnPageLoaded;
        // ItemsControl订阅内容大小变化事件(用于AI回复内容增长时实时滚动)
        // AI回复的内容每多一点那么Size都会变化
        ChatMessagesControl.SizeChanged += OnChatContentSizeChanged;
        // 订阅输入框的按键事件，处理Enter键发送消息
        InputTextBox.PreviewKeyDown += OnInputTextBoxPreviewKeyDown;
    }
    // 【1】页面加载完成时自动滚动：滚动到页面底部
    private void OnPageLoaded(object sender, RoutedEventArgs e)
    {
        // 初次加载时滚动到底部
        ScrollToBottomSmooth();
    }

    // 【2】处理输入框按键事件：Enter执行发送消息命令，Shift+Enter换行
    //  虽然IsDefault="True"按Enter键触发按钮IsCancel="True"按Esc键触发按钮
    //  但是这里会被TextBox的多行输入覆盖掉Enter响应，所以需要手动处理
    private void OnInputTextBoxPreviewKeyDown(object sender, KeyEventArgs e)
    {
        // 只处理Enter键，其他按键不进行任何响应
        if (e.Key != Key.Enter)
            return;
        // 1.如果按下Shift+Enter，允许换行
        if (Keyboard.Modifiers.HasFlag(ModifierKeys.Shift))
        {
            // 允许默认行为（换行）
            return;
        }
        // 2.单独按Enter键，执行发送命令
        e.Handled = true;
        // 阻止默认的换行行为
        if (_viewModel?.SendMessageCommand.CanExecute(null) == true)
        {
            _viewModel.SendMessageCommand.Execute(null);
        }
    }

    // 【3】消息集合变化时智能滚动:只有用户在底部附近时才滚动，避免打扰查看历史消息
    private void OnMessagesCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
    {
        // 只处理新增消息的情况
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            // 智能判断：只有用户在底部附近时才自动滚动
            if (IsUserNearBottom())
            {
                // 延迟一小段时间，确保UI已经更新
                Dispatcher.InvokeAsync(() => ScrollToBottomSmooth(), System.Windows.Threading.DispatcherPriority.Loaded);
            }
        }
    }

    // 【4】AI消息内容增长时实时滚动：适应流式传输渲染
    private void OnChatContentSizeChanged(object sender, SizeChangedEventArgs e)
    {
        // 只有在高度增加且用户在底部附近时才滚动
        if (e.HeightChanged && e.NewSize.Height > e.PreviousSize.Height && IsUserNearBottom())
        {
            // 直接跳转到底部，不使用动画（因为是实时跟随）
            ChatScrollViewer.ScrollToBottom();
        }
    }

    // 辅助方法：判断用户是否在底部附近
    private bool IsUserNearBottom()
    {
        if (ChatScrollViewer == null)
            return true; // 如果ScrollViewer还未初始化，默认返回true
        // 计算当前滚动位置距离底部的距离
        // ScrollableHeight可滚动高度;VerticalOffset已滚动高度，都是只读属性
        double scrollableHeight = ChatScrollViewer.ScrollableHeight;
        double currentOffset = ChatScrollViewer.VerticalOffset;
        double distanceFromBottom = scrollableHeight - currentOffset;
        // 如果距离底部小于阈值，认为用户在底部附近
        return distanceFromBottom <= ScrollThreshold;
    }
    // 辅助方法：平滑滚动到底部
    private void ScrollToBottomSmooth()
    {
        if (ChatScrollViewer == null || _isScrolling)
            return;
        // 确保有可滚动的内容
        ChatScrollViewer.UpdateLayout();
        double targetOffset = ChatScrollViewer.ScrollableHeight;
        double currentOffset = ChatScrollViewer.VerticalOffset;
        // 如果已经在底部，不需要滚动
        if (Math.Abs(targetOffset - currentOffset) < 1)
            return;
        _isScrolling = true;
        // 创建滚动动画,从当前滚动距离到最底部距离
        var animation = new DoubleAnimation
        {
            From = currentOffset,
            To = targetOffset,
            Duration = TimeSpan.FromMilliseconds(300), // 300ms的平滑动画
            EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
        };
        // 动画完成时重置滚动标志
        animation.Completed += (s, e) => _isScrolling = false;
        // 应用动画
        ChatScrollViewer.BeginAnimation(ScrollViewerBehavior.VerticalOffsetProperty, animation);
    }
    // 公共方法：供外部调用强制滚动到底部
    public void ForceScrollToBottom()
    {
        ScrollToBottomSmooth();
    }
}
// 附加属性：ScrollViewer扩展行为，用于支持VerticalOffset的动画
// ScrollViewer原本的VerticalOffset属性不是一个依赖属性，所以不能直接被DoubleAnimation动画驱动。
public static class ScrollViewerBehavior
{
    public static readonly DependencyProperty VerticalOffsetProperty =
        DependencyProperty.RegisterAttached(
            "VerticalOffset",
            typeof(double),
            typeof(ScrollViewerBehavior),
            new PropertyMetadata(0.0, OnVerticalOffsetChanged));

    public static double GetVerticalOffset(DependencyObject obj)
    {
        return (double)obj.GetValue(VerticalOffsetProperty);
    }

    public static void SetVerticalOffset(DependencyObject obj, double value)
    {
        obj.SetValue(VerticalOffsetProperty, value);
    }

    private static void OnVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is ScrollViewer scrollViewer)
        {
            // 【重点】这里才是真正的滚动操作
            scrollViewer.ScrollToVerticalOffset((double)e.NewValue);
        }
    }
}